<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <meta http-equiv="X-UA-Compatible" content="ie=edge"/>
    <title>超大文件上传</title>
</head>

<body>
<button id="submit" onclick="upload.onAdd()">click</button>
<script type="text/javascript">
    var upload = {
        post(url, data) {
            return new Promise((resolve, reject) => {
                var xhr = new XMLHttpRequest();
                xhr.onreadystatechange = () => {
                    let state = xhr.readyState;
                    if (state === 4) {
                        resolve(xhr.responseText);
                    }
                };
                xhr.onerror = err => {
                    reject(err);
                };
                xhr.open("POST", url, false);
                xhr.send(data);
            });
        },
        slice(file, piece = 1024 * 1024 * 5) {
            let totalSize = file.size; // 文件总大小
            let start = 0; // 每次上传的开始字节
            let end = start + piece; // 每次上传的结尾字节
            let chunks = [];
            while (start < totalSize) {
                // 根据长度截取每次需要上传的数据
                // File对象继承自Blob对象，因此包含slice方法
                let blob = file.slice(start, end);
                chunks.push(blob);
                start = end;
                end = start + piece;
            }
            return chunks;
        },
        saveUploadSliceRecord(context, sliceIndex) {
            let list = upload.getUploadSliceRecord(context);
            list.push(sliceIndex);
            localStorage.setItem(context, JSON.stringify(list))
        },
        getUploadSliceRecord(context) {
            let record = localStorage.getItem(context);
            if (!record) {
                return []
            } else {
                try {
                    return JSON.parse(record)
                } catch (e) {
                }
            }
        },
        onAdd() {
            let fileElem = false;
            if (document.getElementById("fileUpdate")) {
                document.getElementById("fileUpdate").remove()
            }
            fileElem = document.createElement("input");
            fileElem.id = "fileUpdate";
            fileElem.type = "file";
            fileElem.style.display = "none";
            fileElem.onchange = function () {
                var file = fileElem.files[0];
                const LENGTH = 1024 * 1024 * 1;
                let chunks = upload.slice(file, LENGTH);
                let fileName = file.name;
                let record = upload.getUploadSliceRecord(fileName);

                let tasks = [];
                chunks.forEach((chunk, index) => {
                    // 已上传的切片则不再重新上传
                    if (record.includes(index)) {
                        return
                    }
                    let fd = new FormData();
                    fd.append("fileName", fileName);
                    fd.append("fileBlob", chunk);
                    fd.append("chunk", index + 1);
                    let task = upload.post("/{$app}/bigFile/upFile", fd).then(res => {
                        // 上传成功后保存已上传切片记录
                        upload.saveUploadSliceRecord(fileName, index);
                        record.push(index);
                    }).catch(err => console.error(err));
                    tasks.push(task);
                });

                Promise.all(tasks).then(res => {
                    let fd = new FormData();
                    fd.append("fileName", fileName);
                    fd.append("chunks", chunks.length);
                    upload.post("/{$app}/bigFile/endFile", fd).then(res => {
                        console.log(res);
                    });
                });
            };
            document.body.appendChild(fileElem);
            if (fileElem) {
                fileElem.click()
            }
        }
    };
</script>
</body>

</html>